package com.xyht.sca_s.student_manage_system.modules.admissionInformation.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ExceptionCast;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ResponseResult;
import com.xyht.sca_s.student_manage_system.common.util.CacheUtil;
import com.xyht.sca_s.student_manage_system.common.util.TimeUtil;
import com.xyht.sca_s.student_manage_system.modules.admissionInformation.entity.SmsAdmissionInformation;
import com.xyht.sca_s.student_manage_system.modules.admissionInformation.entity.req.SmsAdmissionInformationAddReq;
import com.xyht.sca_s.student_manage_system.modules.admissionInformation.entity.req.SmsAdmissionInformationBatchReq;
import com.xyht.sca_s.student_manage_system.modules.admissionInformation.entity.req.SmsAdmissionInformationDeletedReq;
import com.xyht.sca_s.student_manage_system.modules.admissionInformation.entity.req.SmsAdmissionInformationUpdateReq;
import com.xyht.sca_s.student_manage_system.modules.admissionInformation.entity.resp.SmsAdmissionInformationDetailResp;
import com.xyht.sca_s.student_manage_system.modules.admissionInformation.mapper.SmsAdmissionInformationMapper;
import com.xyht.sca_s.student_manage_system.modules.admissionInformation.service.SmsAdmissionInformationService;
import com.xyht.sca_s.student_manage_system.modules.common.entity.SmsImportTask;
import com.xyht.sca_s.student_manage_system.modules.common.entity.SmsImportTaskDetail;
import com.xyht.sca_s.student_manage_system.modules.common.mapper.SmsImportTaskDetailMapper;
import com.xyht.sca_s.student_manage_system.modules.common.mapper.SmsImportTaskMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskDetailReason.*;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskNameExample.TASK_NAME_ADMISSION_INFO_IMPORT;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskStatus.TASK_STATUS_DONE;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskStatus.TASK_STATUS_ERR;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskTypeConstant.TASK_TYPE_ADMISSION_INFO;

/**
 * <p>
 * 录取信息表 服务实现类
 * </p>
 *
 * @author XYHT
 * @since 2023-12-19
 */
@Service
class SmsAdmissionInformationServiceImpl extends ServiceImpl<SmsAdmissionInformationMapper, SmsAdmissionInformation> implements SmsAdmissionInformationService {

    @Resource
    private SmsAdmissionInformationMapper admissionInformationMapper;
    @Resource
    private SmsImportTaskMapper smsImportTaskMapper;
    @Resource
    private SmsImportTaskDetailMapper smsImportTaskDetailMapper;
    @Resource
    private PlatformTransactionManager transactionManager;
    @Resource
    private CacheUtil cacheUtil;

    @Override
    @Async
    public Future<ResponseResult> batchAddAdmissionInformation(Map<String, Object> map, String user_id) {

        JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(map));
        List<SmsAdmissionInformationBatchReq> admissionInfoList = JSONObject.parseArray(JSON.toJSONString(jsonObject.get("list")), SmsAdmissionInformationBatchReq.class);
        if (admissionInfoList == null || admissionInfoList.size() < 1) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
        }
        //创建导入任务
        SmsImportTask smsImportTask = new SmsImportTask();
        smsImportTask.setTaskName(TASK_NAME_ADMISSION_INFO_IMPORT);
        smsImportTask.setUserId(user_id);
        smsImportTask.setTaskType(TASK_TYPE_ADMISSION_INFO);
        smsImportTaskMapper.insert(smsImportTask);
        batchAddAdmissionInfo(admissionInfoList, smsImportTask.getId(),user_id);
        return new AsyncResult<>(CommonResult.success());
    }

    private void batchAddAdmissionInfo(List<SmsAdmissionInformationBatchReq> admissionInfoList, String id, String userId) {
        int OFFSET_ROW = 1;
        int task_status = TASK_STATUS_DONE;
        for (int i = 0; i < admissionInfoList.size(); i++) {
            //开启事务
            DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
            // 嵌套事务 PROPAGATION_REQUIRES_NEW 每次开启一个新的事务
            dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            // 设置嵌套事务
            TransactionStatus status = transactionManager.getTransaction(dt);
            try {
                SmsAdmissionInformationBatchReq storage = admissionInfoList.get(i);
                if (isNullOrEmpty(storage.getIdCard(), storage.getAdmissionTicketNumber(), storage.getExamineeNumber())) {
                    transactionManager.rollback(status);
                    task_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(id, REASON_INVALID_PARAM, (i + OFFSET_ROW) + "");
                    continue;
                }


                //准考证号
                List<SmsAdmissionInformation> admissionInfoByAdmissionTicketList = admissionInformationMapper.selectList(new LambdaQueryWrapper<SmsAdmissionInformation>()
                        .eq(SmsAdmissionInformation::getAdmissionTicketNumber, storage.getAdmissionTicketNumber()));
                if (!admissionInfoByAdmissionTicketList.isEmpty()) {
                    transactionManager.rollback(status);
                    task_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(id, REASON_ADMISSION_TICKET_EXIST, (i + OFFSET_ROW) + "");
                    continue;
                }
                //考生号
                List<SmsAdmissionInformation> admissionInfoByExamineeNumberList = admissionInformationMapper.selectList(new LambdaQueryWrapper<SmsAdmissionInformation>()
                        .eq(SmsAdmissionInformation::getExamineeNumber, storage.getExamineeNumber()));
                if (!admissionInfoByExamineeNumberList.isEmpty()) {
                    transactionManager.rollback(status);
                    task_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(id, REASON_ADMISSION_EXAMINEE_EXIST, (i + OFFSET_ROW) + "");
                    continue;
                }
                //身份证号
                LambdaQueryWrapper<SmsAdmissionInformation> admissionInformationLambdaQueryWrapper = new LambdaQueryWrapper<>();
                admissionInformationLambdaQueryWrapper.eq(SmsAdmissionInformation::getIdCard, storage.getIdCard());
                List<SmsAdmissionInformation> admissionInfoByIdCardList = admissionInformationMapper.selectList(admissionInformationLambdaQueryWrapper);

                SmsAdmissionInformation addAdmissionInformation = new SmsAdmissionInformation();
                BeanUtils.copyProperties(storage, addAdmissionInformation);
                //录取时间
                String admissionTimeStr = storage.getAdmissionTime();
                if (!isNullOrEmpty(admissionTimeStr)) {
                    Date admissionTime = TimeUtil.StringtoDate(admissionTimeStr);
                    if (isNullOrEmpty(admissionTime)) {
                        transactionManager.rollback(status);
                        task_status = TASK_STATUS_ERR;
                        createTeacherImportTaskDetail(id, REASON_ADMISSION_TIME_FORMAT_ERROR, (i + OFFSET_ROW) + "");
                        continue;
                    }
                    addAdmissionInformation.setAdmissionTime(admissionTime);
                }

                addAdmissionInformation.setUserId(userId);
                //修改
                if (!admissionInfoByIdCardList.isEmpty()) {
                   admissionInformationMapper.update(addAdmissionInformation,admissionInformationLambdaQueryWrapper);
                    //新增
                }else {
                    admissionInformationMapper.insert(addAdmissionInformation);
                }

                transactionManager.commit(status);
            } catch (Exception e) {
                transactionManager.rollback(status);
                task_status = TASK_STATUS_ERR;
                createTeacherImportTaskDetail(id, REASON_IMPORT_ERR, (i + OFFSET_ROW) + "");
            } finally {
                if (status.isNewTransaction() && !status.isCompleted()) {
                    transactionManager.commit(status);
                }
            }
        }
        SmsImportTask smsImportTask = new SmsImportTask();
        smsImportTask.setId(id);
        smsImportTask.setStatus(task_status);
        smsImportTaskMapper.updateById(smsImportTask);
    }

    private void createTeacherImportTaskDetail(String id, String reason, String row) {
        SmsImportTaskDetail smsImportTaskDetail = new SmsImportTaskDetail();
        smsImportTaskDetail.setTaskId(id);
        smsImportTaskDetail.setFailReason(reason);
        smsImportTaskDetail.setFailRow(row);
        smsImportTaskDetailMapper.insert(smsImportTaskDetail);
    }

    @Override
    public ResponseResult addAdmissionInformation(SmsAdmissionInformationAddReq addReq, String userId) {
        if (isNullOrEmpty(addReq.getAdmissionTicketNumber(),addReq.getExamineeNumber(),addReq.getIdCard())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        //校验考生号  准考证号
        check(addReq.getExamineeNumber(),addReq.getAdmissionTicketNumber());
        //身份证号
        List<SmsAdmissionInformation> admissionInfoByIdCardList = admissionInformationMapper.selectList(new LambdaQueryWrapper<SmsAdmissionInformation>()
                .eq(SmsAdmissionInformation::getIdCard, addReq.getIdCard()));
        if (!admissionInfoByIdCardList.isEmpty()) {
            return CommonResult.failed(CommonCodeEnum.ADMISSION_ID_CARD_EXIST);
        }
        SmsAdmissionInformation admissionInformation = new SmsAdmissionInformation();
        BeanUtils.copyProperties(addReq,admissionInformation);
        admissionInformation.setUserId(userId);
        admissionInformationMapper.insert(admissionInformation);
        return CommonResult.success();
    }

    @Override
    public ResponseResult deletedAdmissionInformation(SmsAdmissionInformationDeletedReq deletedReq) {
        if (deletedReq.getIdList() == null || deletedReq.getIdList().size() < 1 ) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        List<SmsAdmissionInformation> informationList = admissionInformationMapper.selectBatchIds(deletedReq.getIdList());
        if (informationList.isEmpty()) {
            return CommonResult.failed(CommonCodeEnum.ADMISSION_INFORMATION_NOT_EXIST);
        }
        admissionInformationMapper.deleteBatchIds(deletedReq.getIdList());

        return CommonResult.success();
    }

    @Override
    public ResponseResult updateAdmissionInformation(SmsAdmissionInformationUpdateReq updateReq) {
        if (isNullOrEmpty(updateReq.getId(),updateReq.getAdmissionTicketNumber(),updateReq.getExamineeNumber(),updateReq.getIdCard())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        SmsAdmissionInformation admissionInformation = admissionInformationMapper.selectById(updateReq.getId());
        if (isNullOrEmpty(admissionInformation)) {
            return CommonResult.failed(CommonCodeEnum.ADMISSION_INFORMATION_NOT_EXIST);
        }

        //校验考生号  准考证号
        check(updateReq.getExamineeNumber(),updateReq.getAdmissionTicketNumber());

        BeanUtils.copyProperties(updateReq,admissionInformation);
        admissionInformationMapper.updateById(admissionInformation);

        return CommonResult.success();
    }

    /**
     * 校验 考生号 准考证号
     * @param examineeNumber  考生号
     * @param admissionTicketNumber 准考证号
     */
    private void check(String examineeNumber,String admissionTicketNumber){
        //准考证号
        List<SmsAdmissionInformation> admissionInfoByAdmissionTicketList = admissionInformationMapper.selectList(new LambdaQueryWrapper<SmsAdmissionInformation>()
                .eq(SmsAdmissionInformation::getAdmissionTicketNumber, admissionTicketNumber));
        if (!admissionInfoByAdmissionTicketList.isEmpty()) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.ADMISSION_TICKET_EXIST));
        }
        //考生号
        List<SmsAdmissionInformation> admissionInfoByExamineeNumberList = admissionInformationMapper.selectList(new LambdaQueryWrapper<SmsAdmissionInformation>()
                .eq(SmsAdmissionInformation::getExamineeNumber, examineeNumber));
        if (!admissionInfoByExamineeNumberList.isEmpty()) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.ADMISSION_EXAMINEE_EXIST));
        }
    }

    @Override
    public ResponseResult getAdmissionInformationDetail(String id) {
        if (isNullOrEmpty(id)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        SmsAdmissionInformation admissionInformation = admissionInformationMapper.selectById(id);
        if (isNullOrEmpty(admissionInformation)) {
            return CommonResult.failed(CommonCodeEnum.ADMISSION_INFORMATION_NOT_EXIST);
        }
        SmsAdmissionInformationDetailResp admissionInformationDetailResp = new SmsAdmissionInformationDetailResp();
        BeanUtils.copyProperties(admissionInformation,admissionInformationDetailResp);

        return CommonResult.success(admissionInformationDetailResp);
    }

    @Override
    public ResponseResult getAdmissionInformationList(Integer pageNum, Integer pageSize, String searchStr, String admissionTime) {
        Page<SmsAdmissionInformation> page = new Page<>(pageNum,pageSize);
        LambdaQueryWrapper<SmsAdmissionInformation> admissionInformationLambdaQueryWrapper = new LambdaQueryWrapper<SmsAdmissionInformation>()
                .orderByDesc(SmsAdmissionInformation::getAdmissionTime);

        if (!isNullOrEmpty(searchStr)) {
            admissionInformationLambdaQueryWrapper.and(i -> {
                i.like(SmsAdmissionInformation::getExamineeNumber, searchStr)
                        .or()
                        .like(SmsAdmissionInformation::getAdmissionTicketNumber, searchStr)
                        .or()
                        .like(SmsAdmissionInformation::getIdCard, searchStr);
            });
        }
        if (!isNullOrEmpty(admissionTime)) {
            admissionInformationLambdaQueryWrapper.eq(SmsAdmissionInformation::getAdmissionTime,admissionTime);
        }

        admissionInformationMapper.selectPage(page,admissionInformationLambdaQueryWrapper);
        List<SmsAdmissionInformationDetailResp> informationList = page.getRecords()
                .stream()
                .map(smsAdmissionInformation -> {
                    SmsAdmissionInformationDetailResp admissionInformationDetailResp = new SmsAdmissionInformationDetailResp();
                    BeanUtils.copyProperties(smsAdmissionInformation,admissionInformationDetailResp);
                    return admissionInformationDetailResp;
                })
                .collect(Collectors.toList());
        int total = (int) page.getTotal();
        return CommonResult.success(informationList,total);
    }

    @Override
    public ResponseResult getMyAdmissionInfo(String infoId, String code, String uid) {
        if (isNullOrEmpty(infoId,code,uid)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        List<SmsAdmissionInformation> informationList = admissionInformationMapper.selectList(new LambdaQueryWrapper<SmsAdmissionInformation>()
                .eq(SmsAdmissionInformation::getIdCard, infoId)
                .or()
                .eq(SmsAdmissionInformation::getAdmissionTicketNumber, infoId)
                .or()
                .eq(SmsAdmissionInformation::getExamineeNumber, infoId));
        if (informationList.isEmpty()) {
            return CommonResult.failed(CommonCodeEnum.ADMISSION_INFORMATION_NOT_EXIST);
        }

        //验证码校验
        String upperCode = code.toUpperCase();
        String cacheCode = cacheUtil.getObject(uid,String.class);
        if(cacheCode ==null || !cacheCode.equals(upperCode)){
            return CommonResult.failed(CommonCodeEnum.VERIFY_CODE_CHECK_FAIL);
        }
        SmsAdmissionInformationDetailResp admissionInformationDetailResp = new SmsAdmissionInformationDetailResp();
        BeanUtils.copyProperties(informationList.get(0),admissionInformationDetailResp);
        return CommonResult.success(admissionInformationDetailResp);
    }
}
